/*
 * Eugen Stoian <stoian.e@gmail.com> 2010
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef EXPRESSIONTREENODE_H
#define EXPRESSIONTREENODE_H

#include <QString>
#include <MathParser_global.h>
#include <OperandsException.h>
#include <Real.h>
#include <SmartPtr.h>
/**
  *
  */
class ExpressionTreeNode
{
public:
    /**
     *\fn ExpressionTreeNode()
     *\brief Default constructor
     *
     */
    ExpressionTreeNode();

    /**
     *\fn ~ExpressionTreeNode()
     *\brief Destructor
     *
     */
    virtual ~ExpressionTreeNode() {}

    /**
     *\fn SmartPtr<ExpressionTreeNode> copy() const
     *\brief Returns a deep copy of the tree having as root the current node
     * Reimplemented in derived classes
     *
     */
    virtual ExpressionTreeNode* copy() const = 0;

    /**
     *\fn Real eval(QString & branchPath) const
     *\brief Recursively evaluates contained math expression
     * Reimplemented in derived classes
     *
     */

    virtual Real eval() const = 0;

    /**
     *\fn SmartPtr<ExpressionTreeNode> derive(const QString& varName) const
     *\brief Returns the tree associated to the symbolic math derivative of the contained math expression
     *\param varName Name of the variable with respect to which the derivative is computed
     * Reimplemented in derived classes
     */
    virtual SmartPtr<ExpressionTreeNode> derive(const QString& varName) const = 0;


    SmartPtr<ExpressionTreeNode> simplified() const;

    /**
     *\fn QString info() const
     *\brief Returns the information contained by the node
     * That could be the symbol of the operand, the variable name or the value as a string
     * Reimplemented in derived classes
     */
    virtual QString info() const = 0;

    /**
     *\fn SmartPtr<ExpressionTreeNode> left()
     *\brief Returns a pointer to the left subtree root
     * Reimplemented in derived classes
     *
     */
    inline virtual SmartPtr<ExpressionTreeNode> left() {
        return 0;
    }

    /**
     *\fn const  SmartPtr<ExpressionTreeNode> left() const
     *\brief Returns a constant pointer to the left subtree root
     * Reimplemented in derived classes
     *
     */
    inline virtual const SmartPtr<ExpressionTreeNode> left() const {
        return 0;
    }

    /**
     *\fn void setLeft(SmartPtr<ExpressionTreeNode> node)
     *\brief Assigns the left subtree to the tree having as root the argument passed to the method
     *\param node A pointer to the root of the new left subtree
     * If the left subtree is not null it will be  previously destroyed and memory freed
     * Reimplemented in derived classes
     */
    inline virtual void setLeft(SmartPtr<ExpressionTreeNode> /*node*/)  throw (OperandsException) {
    }

    /**
     *\fn SmartPtr<ExpressionTreeNode> right()
     *\brief Returns a pointer to the right subtree root
     * Reimplemented in derived classes
     *
     */
    inline virtual SmartPtr<ExpressionTreeNode> right() {
        return 0;
    }

    /**
     *\fn const SmartPtr<ExpressionTreeNode> right() const
     *\brief Returns a constant pointer to the right subtree root
     * Reimplemented in derived classes
     *
     */
    inline virtual const SmartPtr<ExpressionTreeNode> right() const {
        return 0;
    }

    /**
     *\fn void setRight(SmartPtr<ExpressionTreeNode> node)
     *\brief Assigns the right subtree to the tree having as root the argument passed to the method
     *\param node A pointer to the root of the new right subtree
     * If the right subtree is not null it will be  previously destroyed and memory freed
     * Reimplemented in derived classes
     */
    inline virtual void setRight(SmartPtr<ExpressionTreeNode>  /*node*/)  throw (OperandsException) {
    }

    /**
     *\fn bool isOperand() const
     *\brief Returns true if the node is a value or a variable
     * Reimplemented in derived classes
     *
     */
    inline bool isOperand() const {
        return isValue()||isVariable();
    }

    /**
     *\fn bool isOp() const
     *\brief Returns true if the node is an operator (binary or unary)
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isOp() const {
        return isUnaryOp()||isBinaryOp();
    }

    /**
     *\fn bool isBinaryOp() const
     *\brief Returns true if the node is a binary operator
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isBinaryOp() const {
        return false;
    }

    /**
     *\fn bool isUnaryOp() const
     *\brief Returns true if the node is an unary operator
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isUnaryOp() const {
        return false;
    }

    /**
     *\fn bool isVariable() const
     *\brief Returns true if the node is a variable
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isVariable() const {
        return false;
    }

    /**
     *\fn bool isValue() const
     *\brief Returns true if the node is a value
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isValue() const {
        return false;
    }
    /**
     *\fn bool isMathConstant() const
     *\brief Returns true if the node is a math constant
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isMathConstant() const {
        return false;
    }
    /**
     *\fn bool isConditionalOp() const
     *\brief Returns true if the node is a condition
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isConditionalOp() const {
        return false;
    }
    /**
     *\fn bool isBooleanOp() const
     *\brief Returns true if the node is a condition
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isBooleanOp() const {
        return false;
    }

    /**
     *\fn bool isRelationalOp() const
     *\brief Returns true if the node is a condition
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isRelationalOp() const {
        return false;
    }

     /*\fn bool isBoolean() const
     *\brief Returns true if the node is a condition
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isBoolean() const {
        return isBooleanOp()||isValue();
    }

    /**
     *\fn bool isArithmeticOp() const
     *\brief Returns true if the node is a condition
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isArithmeticOp() const {
        return false;
    }

    /**
     *\fn bool isArithmetic() const
     *\brief Returns true if the node is a condition
     * Reimplemented in derived classes
     *
     */
    inline virtual bool isArithmetic() const {
        return isArithmeticOp()||isOperand();
    }

    /**
     *\fn QString toPrefixString() const
     *\brief
     *
     */
    virtual QString toPrefixString() const = 0;


    /**
     *\fn QString toPostfixString() const
     *\brief
     *
     */
    virtual QString toPostfixString() const = 0;


    /**
     *\fn QString toInfixString() const
     *\brief
     *
     */
    virtual QString toInfixString() const = 0;


    /**
     *\fn int precedence() const
     *\brief
     *
     */
    virtual int precedence() const = 0;

    /**
     *\fn SmartPtr<ExpressionTreeNode> firstLevelSimplification() const
     *\brief Returns the root of first level simplification expression tree
     */
    virtual SmartPtr<ExpressionTreeNode> firstLevelSimplification() const = 0;



    /**
     *\fn void bind(const QString& varName, Real * var) const
     *\brief
     *
     */
    virtual void bind(const QString& varName,  const Real * var) const = 0;

    /**
     *\fn void bind(int varPos& varName, Real * var) const
     *\brief
     *
     */
    virtual void bind(int varPos,  const Real * var) const = 0;

    /**
     *\fn EpressionTreeNode* replace(const QString& varName, ExpressionTreeNode* tree) const
     *\brief
     *
     */
    virtual ExpressionTreeNode* replace(const QString& varName, ExpressionTreeNode* tree) const = 0;

    /**
     *\fn EpressionTreeNode* replace(int varPos, ExpressionTreeNode* tree) const
     *\brief
     *
     */
    virtual ExpressionTreeNode* replace(int varPos, ExpressionTreeNode* tree) const = 0;

    const QString& marker() const {
        return _marker;
    }

    virtual void resetMarker() const = 0;

protected:
    mutable QString _marker;

};

typedef SmartPtr<ExpressionTreeNode> ExpressionTree;
typedef ExpressionTree (*ExpressionTreeOp)(ExpressionTree, const QString&);

#endif // EXPRESSIONTREENODE_H
